<template>
  <div
    class="chart-container"
    :style="{ width: width, height: height, background: background }"
  >
    <div class="chart-controls">
      <div class="ma-show">
        <div class="label">MA</div>
        <dl v-for="ma in maTypes" :key="ma.value" :style="{ color: ma.color }">
          <dt>{{ ma.label }}</dt>
          <dd>{{ currentMAValues[`MA${ma.value}`] }}</dd>
        </dl>
      </div>
      <div class="zoom-controls">
        <!-- <button @click="toggleSBT" class="sbt-button">SBT</button> -->
        <!-- <button @click="zoomChart(0.8)">+</button>
        <button @click="zoomChart(1.2)">-</button> -->
      </div>
    </div>
    <div ref="mainChart" class="main-chart"></div>
    <div ref="volumeChart" class="volume-chart"></div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, watch } from "vue";
import * as echarts from "echarts";
const props = defineProps({
  stockData: {
    type: Array,
    required: true,
    validator: (value) =>
      value.every((item) => Array.isArray(item) && item.length >= 8),
  },
  width: {
    type: String,
    required: false,
    default: "1000px",
  },
  height: {
    type: String,
    required: false,
    default: "650px",
  },
  background: {
    type: String,
    required: false,
    default: "#fff",
  },
});
watch(
  () => props.stockData,
  (newVal) => {
    if (newVal.length > 0) {
      const dataLength = newVal.length;
      currentStart.value = Math.max(0, dataLength - windowSize);
      currentEnd.value = dataLength - 1;
      updateCharts();
    }
  }
);
const mainChart = ref(null);
const volumeChart = ref(null);
let mainInstance = null;
let volumeInstance = null;
const windowSize = 30;
const currentStart = ref(0);
const currentEnd = ref(29);
const startDate = ref("");
const endDate = ref("");
const maTypes = ref([
  { label: "5", value: 5, color: "#8adc87" },
  { label: "10", value: 10, color: "#4db9b8" },
  { label: "20", value: 20, color: "#2841a3" },
  { label: "50", value: 50, color: "#9b3bac" },
]);
const showSBT = ref(true);

// 鼠标交互状态
const currentMAValues = ref({ MA5: 0, MA10: 0, MA20: 0, MA50: 0 });

// 修改后的生成函数
const generateMarkerSVG = (color, isTop, type, groupOrder) => {
  const lineY1 = 15; // 降低中心点高度
  const lineY2 = isTop ? 30 + 10 * groupOrder : 0 - 10 * groupOrder; // 缩小连线长度
  const rectSize = 10; // 缩小矩形尺寸
  const rectX = 10 - rectSize / 2; // 调整水平位置
  const rectY = 15 - rectSize / 2; // 调整垂直位置

  return (
    `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="${
      30 + 10 * groupOrder
    }" viewBox="0 0 20 30">` +
    `<line x1="10" y1="${lineY1}" x2="10" y2="${lineY2}" stroke="#ccc" stroke-width="0.5" stroke-dasharray="1 1"/>` +
    `<rect x="${rectX}" y="${rectY}" width="${rectSize}" height="${rectSize}" ` +
    `fill="${color}" stroke="#fff" stroke-width="0.5" rx="1"/>` +
    `<text x="10" y="${
      15 + 2
    }" text-anchor="middle" font-size="7" fill="#fff">${getSignalName(
      type
    )}</text>` +
    `</svg>`
  );
};
// 核心数据处理函数
const processData = () => {
  let upGroupIndex = 0; // 上方标记点组内计数器
  let downGroupIndex = 0; // 下方标记点组内计数器
  let validMarkCount = 0; // 有效信号点总数
  const allMarkers = props.stockData
    .map((item, index) => {
      // item[7] = Math.floor(Math.random() * 4);
      if (item[7] > 0) {
        //判断有没有SBT点
        validMarkCount++;
        // 相邻两个点交替上下
        const isTop = validMarkCount % 2 === 1;

        // 计算基础价格位置
        const basePrice = isTop ? item[4] : item[3]; // 上方用收盘价，下方用最低价
        // 动态计算偏移量
        let offsetY, groupOrder;
        let groupIndex = 0;
        let offsetSize = 12;
        if (isTop) {
          upGroupIndex++;
          groupOrder = (upGroupIndex - 1) % 4;
          offsetY = -offsetSize - groupOrder * 8; // 上方组内偏移
          groupIndex = groupOrder;
        } else {
          downGroupIndex++;
          groupOrder = (downGroupIndex - 1) % 4;
          offsetY = offsetSize + groupOrder * 8; // 下方组内偏移
          groupIndex = groupOrder;
        }
        const svgString = generateMarkerSVG(
          getSignalColor(item[7]),
          isTop,
          item[7],
          groupIndex
        );
        return {
          xAxis: index,
          yAxis: basePrice,
          value: item[7],
          name: getSignalName(item[7]),
          itemStyle: {
            color: getSignalColor(item[7]),
          },
          symbol: `image://data:image/svg+xml;base64,${window.btoa(
            unescape(encodeURIComponent(svgString))
          )}`,
          symbolSize: [20, 30 + groupIndex * 10], // 缩小符号尺寸
          symbolOffset: [0, offsetY * 0.6], // 减小偏移量倍数
          symbolLabel: {
            show: false,
          },
        };
      }
      return null;
    })
    .filter(Boolean);

  return {
    times: props.stockData.map((item) => item[0]),
    ohlc: props.stockData.map((item) => [item[1], item[2], item[3], item[4]]),
    volumes: props.stockData.map((item, index) => {
      const [open, close] = [item[1], item[2]];
      let fillColor, borderColor;

      // 十字星判断
      if (open === close) {
        const prevClose = index > 0 ? props.stockData[index - 1][2] : close;
        fillColor = close >= prevClose ? "#fff" : "#00a674"; // 白色填充
        borderColor = close >= prevClose ? "#b95f6c" : "#00a674"; // 边框色判断
      }
      // 常规K线
      else {
        fillColor = close > open ? "#fff" : "#00a674";
        borderColor = close > open ? "#b95f6c" : "#00a674";
      }

      return {
        value: item[5],
        itemStyle: {
          color: fillColor,
          borderColor: borderColor,
          borderWidth: 1,
        },
      };
    }),
    bstMarkers: allMarkers,
    ma5: calculateMA(5),
    ma10: calculateMA(10),
    ma20: calculateMA(20),
    ma50: calculateMA(50),
  };
};

// 辅助函数
const getSignalName = (type) => {
  switch (type) {
    case 1:
      return "S";
    case 2:
      return "B";
    case 3:
      return "T";
    default:
      return "";
  }
};

const getSignalColor = (type) => {
  switch (type) {
    case 1:
      return "#b95f6c";
    case 2:
      return "#00a674";
    case 3:
      return "#f3d214";
    default:
      return "";
  }
};

const calculateMA = (dayCount) => {
  const result = [];
  const closePrices = props.stockData.map((item) => item[2]);
  for (let i = 0; i < closePrices.length; i++) {
    if (i < dayCount - 1) {
      result.push("-");
      continue;
    }
    const slice = closePrices.slice(Math.max(0, i - dayCount + 1), i + 1);
    result.push(+(slice.reduce((a, b) => a + b, 0) / dayCount).toFixed(3));
  }
  return result;
};
const toggleSBT = () => {
  showSBT.value = !showSBT.value;
  updateCharts();
};
// 图表配置生成器
const getMainOption = (data) => {
  return {
    textStyle: {
      fontFamily: "Microsoft YaHei, PingFang SC, sans-serif", // 优先使用雅黑，回退苹方/系统无衬线
    },
    animation: false,
    tooltip: {
      trigger: "axis",
      formatter: function () {
        return "";
      },
      axisPointer: {
        type: "cross",
      },
      borderColor: "transparent",
      backgroundColor: "transparent",
    },
    graphic: [],
    grid: {
      top: 0,
      left: 5,
      right: 5,
      bottom: 5,
      containLabel: false,
      show: true,
      borderColor: "#e5e5e5",
      borderWidth: 1,
    },
    xAxis: {
      show: false,
      type: "category",
      axisTick: {
        show: false,
      },
      axisPointer: {
        z: 10000,
        label: {
          backgroundColor: "rgba(110, 110, 118,.8)",
          show: false,
        },
      },
      data: data.times,
      boundaryGap: [0, 20],
      axisLine: { lineStyle: { color: "#e5e5e5" }, onZero: false },
    },
    yAxis: {
      position: "right",
      scale: true,
      offset: 6, // 右侧偏移补偿[2](@ref)
      axisTick: {
        show: false,
      },
      axisPointer: {
        z: 10000,
        label: {
          backgroundColor: "rgba(110, 110, 118,.8)",
        },
      },
      axisLine: { lineStyle: { color: "#e5e5e5" } },
      splitLine: { lineStyle: { type: "solid", color: "rgba(0,0,0,.1)" } },
      splitNumber: 3,
      z: 150,
      axisLabel: {
        inside: true,
        showMaxLabel: true,
        color: "#222",
        verticalAlign: "bottom",
        fontSize: 14,
        verticalAlignMaxLabel: "top",
        textBorderWidth: 1,
        textBorderColor: "#fff",
        lineHeight: 18,
        formatter: (value) => {
          return value.toFixed(2);
        },
      },
    },
    dataZoom: [
      {
        type: "inside",
        xAxisIndex: 0,
        startValue: currentStart.value,
        endValue: currentEnd.value,
        minValueSpan: 29,
        maxValueSpan: 99,
      },
    ],
    series: [
      {
        name: "K线",
        type: "candlestick",
        z: 110,
        data: data.ohlc,
        barWidth: "75%",
        itemStyle: {
          color: "#fff",
          color0: "#00a674",
          borderColor: "#b95f6c",
          borderColor0: "#00a674",
          borderWidth: 1,
          emphasis: {
            // 禁用高亮样式
            color: "#fff",
            color0: "#00a674",
            borderColor: "#b95f6c",
            borderColor0: "#00a674",
            borderWidth: 1,
          },
        },
        markPoint: showSBT.value
          ? {
              data: data.bstMarkers,
              z: 100,
              silent: true,
              symbolSize: 30,
              itemStyle: {
                color: (params) => params.data.itemStyle.color,
                borderColor: "#fff",
                borderWidth: 1,
              },
              label: {
                show: true,
                formatter: (params) => params.data.name,
                color: "#fff",
                fontSize: 9,
                position: "middle",
              },
            }
          : {
              // 隐藏时配置
              data: [],
              symbolSize: 0,
              itemStyle: {
                color: "transparent",
              },
            },
      },
      ...maTypes.value.map((ma) => ({
        name: `MA${ma.value}`,
        type: "line",
        data: data[`ma${ma.value}`],
        smooth: true,
        showSymbol: false,
        lineStyle: {
          width: 1,
          color: ma.color,
          type: "solid", // 50日均线用虚线
        },
        animation: false,
      })),
    ],
  };
};

const getVolumeOption = (data) => {
  const visibleVolumes = data.volumes.slice(
    currentStart.value,
    currentEnd.value + 1
  );
  const maxVolume = Math.max(...visibleVolumes.map((v) => v.value)) || 0; // 防止空数据报错
  return {
    textStyle: {
      fontFamily: "Microsoft YaHei, PingFang SC, sans-serif", // 优先使用雅黑，回退苹方/系统无衬线
    },
    animation: false,
    grid: {
      top: 5,
      left: 5,
      right: 5,
      bottom: 25,
      containLabel: true,
      show: true,
      borderColor: "#e5e5e5",
      borderWidth: 1,
    },
    xAxis: {
      type: "category",
      data: data.times,
      boundaryGap: [0, 20],
      axisLine: { show: false },
      axisLabel: {
        show: false,
      },
      axisTick: {
        show: false,
      },

      axisPointer: {
        z: 10000,
        label: {
          backgroundColor: "rgba(110, 110, 118,.8)",
          show: true,
        },
      },
    },
    yAxis: [
      {
        name: "",
        position: "right",
        boundaryGap: [0, 20],
        scale: true,
        axisLine: { show: false },
        splitLine: { show: false },
        max: "dataMax",
        splitNumber: 2,
        axisLabel: {
          inside: false,
          show: false,
        },
        axisTick: {
          show: false,
        },
      },
    ],
    graphic: [
      {
        type: "text",
        left: "5",
        bottom: "5",
        z: 100,
        style: {
          text: startDate.value,
          fill: "#333",
          fontSize: 12,
        },
      },
      {
        type: "text",
        right: "5",
        bottom: "5",
        z: 100,
        style: {
          text: endDate.value,
          fill: "#333",
          fontSize: 12,
        },
      },
      {
        type: "text",
        right: "6",
        top: "6", // 右上角位置
        z: 100,
        style: {
          text: `${(maxVolume / 10000).toFixed(1) + "万"}`,
          fill: "#333",
          fontSize: 14,
          textAlign: "right", // 右对齐更美观
        },
      },
      {
        type: "group",
        left: "5",
        top: "5", // 右上角位置
        children: [
          {
            type: "rect",
            left: "center",
            top: "center",
            z: 100,
            shape: {
              width: 40,
              height: 20,
            },
            style: {
              fill: "rgba(0,0,0,.15)",
              stroke: "rgba(0,0,0,.11)",
            },
          },
          {
            type: "text",
            left: "center",
            top: "center",
            z: 100,
            style: {
              text: `VOL`,
              fill: "#333",
              fontSize: 10,
              fontWeight: "bold",
            },
          },
        ],
      },
    ],
    tooltip: {
      trigger: "axis",
      showContent: false,
      axisPointer: {
        type: "line",
        label: {
          backgroundColor: "#6a7985",
        },
      },
    },
    dataZoom: [
      {
        type: "inside",
        xAxisIndex: 0,
        startValue: currentStart.value,
        endValue: currentEnd.value,
        minValueSpan: 29,
        maxValueSpan: 99,
      },
    ],
    series: [{
      name: "成交量",
      type: "bar",
      data: data.volumes.map(item => ({
        value: item.value,
        itemStyle: {
          color: item.itemStyle.color,
          borderColor: item.itemStyle.borderColor,
          borderWidth: item.itemStyle.borderWidth,
          emphasis: {
            color: item.itemStyle.color,
            borderColor: item.itemStyle.borderColor,
            borderWidth: item.itemStyle.borderWidth
          }
        }
      })),
      barWidth: "75%"
    }],
  };
};
const formatDate = (timestamp) => {
  const date = new Date(timestamp);
  return `${date.getFullYear()}/${(date.getMonth() + 1)
    .toString()
    .padStart(2, "0")}/${date.getDate().toString().padStart(2, "0")}`;
};
const updateCharts = () => {
  const chartData = processData();
  mainInstance.setOption(getMainOption(chartData));
  volumeInstance.setOption(getVolumeOption(chartData));

  echarts.connect([mainInstance, volumeInstance]);
};

const zoomChart = (ratio) => {
  const chartData = processData();
  startDate.value = formatDate(chartData.times[currentStart.value]);
  endDate.value = formatDate(chartData.times[currentEnd.value]);

  // 修正窗口大小计算
  const visibleDataCount = currentEnd.value - currentStart.value + 1;
  const newWindowSize = Math.floor(visibleDataCount * ratio);
  const maxWindowSize = 100; // 新增最大窗口限制

  // 限制窗口大小在30-100之间
  const clampedSize = Math.min(
    Math.max(newWindowSize, windowSize),
    maxWindowSize
  );

  // 保持当前可视区域中心点
  const centerIndex = Math.floor((currentStart.value + currentEnd.value) / 2);

  // 计算新的起止位置
  currentStart.value = Math.max(0, centerIndex - Math.floor(clampedSize / 2));
  currentEnd.value = currentStart.value + clampedSize - 1; // 直接基于窗口大小计算

  // 确保不越界
  currentEnd.value = Math.min(props.stockData.length - 1, currentEnd.value);

  // 更新日期显示
  startDate.value = formatDate(chartData.times[currentStart.value]);
  endDate.value = formatDate(chartData.times[currentEnd.value]);

  updateCharts();
};
const handleChartHover = (params) => {
  if (!params || !mainInstance) return;

  const pointInPixel = [params.offsetX, params.offsetY];
  const pointInGrid = mainInstance.convertFromPixel("grid", pointInPixel);

  if (pointInGrid[0] < 0 || pointInGrid[1] < 0) return;

  const dataIndex = Math.round(pointInGrid[0]);
  let datad = processData();
  currentMAValues.value = {
    MA5: datad.ma5[dataIndex] || 0,
    MA10: datad.ma10[dataIndex] || 0,
    MA20: datad.ma20[dataIndex] || 0,
    MA50: datad.ma50[dataIndex] || 0,
  };

  mainInstance.setOption({
    graphic: [
      {
        type: "line",
        position: pointInPixel,
        shape: { y1: pointInPixel[1], y2: pointInPixel[1] },
        invisible: false,
      },
    ],
  });
};

// 生命周期管理
const initCharts = () => {
  const chartData = processData();
  const dataLength = chartData.times.length;
  currentStart.value = Math.max(0, dataLength - windowSize);
  currentEnd.value = dataLength - 1;
  startDate.value = formatDate(chartData.times[currentStart.value]);
  endDate.value = formatDate(chartData.times[currentEnd.value]);
  mainInstance = echarts.init(mainChart.value);
  volumeInstance = echarts.init(volumeChart.value);
  // 设置初始MA值为最后一天的有效值
  const getLastValidMA = (maArray) => {
    for (let i = maArray.length - 1; i >= 0; i--) {
      if (maArray[i] !== "-") return maArray[i];
    }
    return 0;
  };
  currentMAValues.value = {
    MA5: getLastValidMA(chartData.ma5),
    MA10: getLastValidMA(chartData.ma10),
    MA20: getLastValidMA(chartData.ma20),
    MA50: getLastValidMA(chartData.ma50),
  };
  const updateZoom = () => {
    const option = mainInstance.getOption();
    const dataZoom = option.dataZoom[0];
    currentStart.value = dataZoom.startValue;
    currentEnd.value = dataZoom.endValue;
    startDate.value = formatDate(chartData.times[currentStart.value]);
    endDate.value = formatDate(chartData.times[currentEnd.value]);
    updateCharts();
  };
  const mainOption = getMainOption(chartData);
  const volumeChartOption = getVolumeOption(chartData);
  // const chartWidth = mainChart.value.offsetWidth;
  // const chartHeight = mainChart.value.offsetHeight;
  // const positions = [
  //   chartWidth * 0.25, // 1/4处
  //   chartWidth * 0.5, // 中间
  //   chartWidth * 0.75, // 3/4处
  // ];

  // 动态生成 graphic 配置
  // const verticalLines = positions.map((x) => ({
  //   type: "line",
  //   silent: true,
  //   shape: {
  //     x1: x,
  //     y1: mainOption.grid.top,
  //     x2: x,
  //     y2: chartHeight - mainOption.grid.bottom,
  //   },
  //   style: { stroke: "#eee", lineWidth: 1 },
  //   z: 0,
  // }));
  // mainOption.graphic = [...mainOption.graphic, ...verticalLines];
  // const volumeChartWidth = volumeChart.value.offsetWidth;
  // const volumeChartHeight = volumeChart.value.offsetHeight;
  // const volumeChartpositions = [
  //   volumeChartWidth * 0.25, // 1/4处
  //   volumeChartWidth * 0.5, // 中间
  //   volumeChartWidth * 0.75, // 3/4处
  // ];

  // 动态生成 graphic 配置
  // const volumeChartverticalLines = volumeChartpositions.map((x) => ({
  //   type: "line",
  //   silent: true,
  //   shape: {
  //     x1: x,
  //     y1: volumeChartOption.grid.top,
  //     x2: x,
  //     y2: volumeChartHeight - volumeChartOption.grid.bottom,
  //   },
  //   style: { stroke: "#e5e5e5", lineWidth: 1 },
  //   z: 0,
  // }));
  // mainOption.graphic = [...mainOption.graphic, ...verticalLines];
  // volumeChartOption.graphic = [
  //   ...volumeChartOption.graphic,
  //   ...volumeChartverticalLines,
  // ];
  mainInstance.setOption(mainOption);
  volumeInstance.setOption(volumeChartOption);
  mainInstance.on("dataZoom", updateZoom);
  volumeInstance.on("dataZoom", updateZoom);

  mainInstance.getZr().on("mousemove", handleChartHover);
  mainInstance.getZr().on("mouseout", () => {
    mainInstance.setOption({ graphic: [{ invisible: true }] });
  });

  echarts.connect([mainInstance, volumeInstance]);
  setTimeout(() => {
    console.log(mainInstance.getOption());
  }, 5000);
};

const handleResize = () => {
  mainInstance?.resize();
  volumeInstance?.resize();
};

onMounted(() => {
  initCharts();
  window.addEventListener("resize", handleResize);
});

onBeforeUnmount(() => {
  window.removeEventListener("resize", handleResize);
  mainInstance?.dispose();
  volumeInstance?.dispose();
});
</script>

<style lang="less" scoped>
.chart-container {
  width: 1000px;
  height: 650px;
  background: var(--chart-bg);
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: #ddd 1px solid;
}
.chart-controls {
  z-index: 1;
  display: flex;
  justify-content: space-between;
}

.ma-show {
  display: flex;
  gap: 10px;
  .label {
    font-size: 12px;
    font-weight: bold;
    background: #e4eae8;
    padding: 0 8px;
    height: 28px;
    line-height: 28px;
  }
  dl {
    line-height: 14px;
    gap: 1px;
    font-weight: normal;
    display: flex;
    gap: 4px;
    line-height: 28px;
    dt {
      font-size: 14px;
      font-weight: bold;
      color: #f1a263;
    }
    dd {
      font-size: 14px;
    }
  }
}
.zoom-controls {
  display: flex;
  gap: 8px;
  // display: none;
  button {
    padding: 0 8px;
    height: 20px;
    min-width: 20px;
    font-size: 12px;
    font-weight: bold;
    &.sbt-button {
      font-size: 10px;
      font-weight: normal;
      position: relative;
      top: 4px;
    }
  }
}
.main-chart {
  flex: 7;
}

.volume-chart {
  flex: 3;
}

@media (prefers-color-scheme: dark) {
  :root {
    --chart-bg: #1a1a1a;
    --chart-border: #333;
  }
}
</style>